#include <iostream>
#include <malloc.h>
#include <string>
#include <readline/readline.h>
#include <readline/history.h>

extern "C"char *xmalloc (int);

#include "atom.h"
#include "input.h"
#include "prover.h"

using namespace Input;

// Path to the executable; reference path for loading modules
std::string Input::singlogPath;

bool Input::getLine (std::string &line, bool prompt) {
  const char *promptString = (prompt ? "=> " : "   ");

  /*   // Using traditional iostream
   std::cout << promptString;
   getline (std::cin, line);*/

  line.clear ();

  rl_readline_name = "singlog";
  char *p = readline (promptString);
  if(p) {
    line = p;
    if(prompt && *p)
      add_history (p);
    free (p);
    return true;
  } else
    return false;
}

Rules *rulesForCommandCompletion;

char *commandCompletionGenerator (const char *text, int state) {

  // Iterators for system predicates and atom names
  // (Something minor... this violates encapsulation)
  static Atom::AtomPool::Atoms::iterator atomIter, atomEnd;
  static size_t length;
  const char *name;

  if(!state) {
    atomIter = Atom::atomPool->atoms.lower_bound (text);
    atomEnd = Atom::atomPool->atoms.end ();
    length = strlen (text);
  }

  if(atomIter != atomEnd) {
    name = (*atomIter).first;
    if(strncmp (name, text, length) == 0 && isalnum (name[0])) {
      char *ret = xmalloc (strlen (name) + 1);
      strcpy (ret, name);
      atomIter++;
      return ret;
    }
  }

  return (char*) NULL;
}

char **commandCompletion (const char *text, int, int) {
  char **matches = 0;
  matches = rl_completion_matches (text, commandCompletionGenerator);
  return matches;
}

void Input::setCommandCompletion (Rules &r) {
  rulesForCommandCompletion = &r;
  rl_attempted_completion_function = commandCompletion;
}

// Concatenates a line from a file to an input string
void Input::concatLine (std::string &input, std::string &line) {

  // Removes UTF-8 file identifier
  if(line.substr (0, 3) == "\xEF\xBB\xBF")
    line.erase (0, 3);

  // Chomps line feed
  if(*(line.end () - 1) == '\r')
    line.erase (line.end () - 1);

  // Remove comments anyway, or line reader may not detect the rule-end '#'
  std::string::size_type len = line.length ();
  int inQuote = 0;
  if(len)
    for(std::string::size_type i = 0; i < len - 1; i++) {
      if(line[i] == '\'' && inQuote != 2)
        inQuote = 1 - inQuote;
      if(line[i] == '"' && inQuote != 1)
        inQuote = 2 - inQuote;
      if(line[i] == '-' && line[i + 1] == '-' && !inQuote) {
        line.erase (i);
        break;
      }
    }

  line = trim (line);

  if(input.length ())
    input += '\n' + line;
  else
    input += line;
}
